package com.dongdongshop.service.impl;

import com.alibaba.dubbo.config.annotation.Service;
import com.dongdongshop.mapper.TbSeckillGoodsMapper;
import com.dongdongshop.pojo.seckill.TbSeckillGoods;
import com.dongdongshop.pojo.seckill.TbSeckillGoodsExample;
import com.dongdongshop.pojo.seckill.TbSeckillOrder;
import com.dongdongshop.service.seckill.SeckillService;
import com.dongdongshop.util.IdWorker;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.util.Date;
import java.util.List;

/**
 * @Author Eayon
 * @Date 2020/3/17 11:28
 */
@Service
@Component
public class SeckillServiceImpl implements SeckillService {

    @Resource
    private TbSeckillGoodsMapper seckillGoodsMapper;

    @Resource
    private RedisTemplate redisTemplate;

    @Resource
    private IdWorker idWorker;

    /**
     * 查询所有状态良好的秒杀商品
     * @return
     */
    @Override
    public List<TbSeckillGoods> findSeckillGoodsAll() {
        //先从缓存中获取秒杀商品缓存数据
        List<TbSeckillGoods> seckillGoodsList = redisTemplate.boundHashOps("seckillGoods").values();
        if(seckillGoodsList == null || seckillGoodsList.size() <= 0){
            //如果查出来的为空说明缓存中没有，那么就从数据库中查询出来
            TbSeckillGoodsExample example = new TbSeckillGoodsExample();
            TbSeckillGoodsExample.Criteria criteria = example.createCriteria();
            criteria.andStatusEqualTo("1");//审核状态为1的 通过的
            criteria.andStartTimeLessThanOrEqualTo(new Date());//商品秒杀开始时间小于等于当前系统时间的
            criteria.andEndTimeGreaterThanOrEqualTo(new Date());//商品秒杀结束时间大于等于当前系统时间的
            criteria.andStockCountGreaterThan(0);//当前秒杀商品库存余数大于0的
            //将查询出来的数据赋值给上面的空集合，然后下面return
            seckillGoodsList = seckillGoodsMapper.selectByExample(example);
            //存入缓存
            for (TbSeckillGoods tbSeckillGoods : seckillGoodsList) {
                redisTemplate.boundHashOps("seckillGoods").put(tbSeckillGoods.getId(),tbSeckillGoods);
                redisTemplate.boundHashOps("seckillStockCount").put(tbSeckillGoods.getId(),tbSeckillGoods.getStockCount());
            }
        }
        //如果不为空就直接返回
        return seckillGoodsList;
    }

    /**
     * 从redis缓存中
     * 根据秒杀商品id查询秒杀商品信息
     * @param id
     * @return
     */
    @Override
    public TbSeckillGoods getSeckillById(Long id) {
        return (TbSeckillGoods)redisTemplate.boundHashOps("seckillGoods").get(id);
    }

    /**
     * 秒杀下单 提交订单
     * @param seckillId
     * @param userId
     */
    @Override
    public void submitOrder(Long seckillId, Long userId) {
        //从redis中获取该秒杀商品信息
        TbSeckillGoods seckillGoods = (TbSeckillGoods)redisTemplate.boundHashOps("seckillGoods").get(seckillId);
        //如果商品不存在就抛一个异常，然后调用者处理一下就好了
        if(seckillGoods==null){
            throw new RuntimeException("商品不存在");
        }
        //如果商品存在但没有库存也抛异常
        if(seckillGoods.getStockCount() <= 0){
            throw new RuntimeException("商品库存不足");
        }
        //先扣除库存
        seckillGoods.setStockCount(seckillGoods.getStockCount()-1);
        //再重新放回缓存
        redisTemplate.boundHashOps("seckillGoods").put(seckillGoods.getId(),seckillGoods);
        //如果口见过库存之后，商品的剩余库存为0 也就是正好现在是最后一个 也卖掉了情况
        if(seckillGoods.getStockCount() == 0){
            //将数据同步到数据库中，只有当缓存中剩余库存为0的时候才同步数据库，减少数据库压力
            seckillGoodsMapper.updateByPrimaryKey(seckillGoods);
            //并且删除缓存中该秒杀商品
            redisTemplate.boundHashOps("seckillGoods").delete(seckillId);
        }
        //保存秒杀订单到redis当中
        long seckillOrderId = idWorker.nextId();//秒杀订单id
        //构建商品订单对象 并赋值
        TbSeckillOrder seckillOrder = new TbSeckillOrder();
        seckillOrder.setId(seckillOrderId);//生成的订单id
        seckillOrder.setCreateTime(new Date());//订单创建时间
        seckillOrder.setMoney(seckillGoods.getCostPrice());//秒杀价
        seckillOrder.setSeckillId(seckillId);//商品id
        seckillOrder.setSellerId(seckillGoods.getSellerId());//卖家ID
        seckillOrder.setUserId(userId.toString());//买家id
        seckillOrder.setStatus("0");//订单状态  待付款
        //根据买家id保存秒杀商品订单到redis中
        redisTemplate.boundHashOps("seckillOrder").put(userId,seckillOrder);
    }
}
